#include "N0Lib.h"

#ifdef WINDOWS

#include "N2Win32Drawer.h"

N2Win32Drawer::N2Win32Drawer(HDC hdc) : m_dc(hdc), m_color(0)
{
    createPen(m_color);
    m_brush = new N2Brush(N2Color::whiteColor());
    createBrush(m_brush->fillColor());
    setSize();
}

N2Win32Drawer::~N2Win32Drawer()
{
    m_brush->retain();
}

POINT* N2Win32Drawer::allocPoints(uint32 count)
{
    return (POINT*)N1Malloc(count * sizeof(POINT));
}

void   N2Win32Drawer::freePoints(POINT* pnts)
{
    N1Free(pnts);
}

void  N2Win32Drawer::createPen(COLORREF color)
{
    HPEN pen = ::CreatePen(PS_SOLID, 1, color);
    HPEN oldPen = (HPEN)::SelectObject(m_dc, pen);
    ::DeleteObject(oldPen);
}

void  N2Win32Drawer::createBrush(COLORREF color)
{
    HBRUSH brush = ::CreateSolidBrush(color);
    HBRUSH oldBrush = (HBRUSH)::SelectObject(m_dc, brush);
    ::DeleteObject(oldBrush);
}

void N2Win32Drawer::setSize()
{
    int horz = ::GetDeviceCaps(m_dc, HORZRES);
    int vert = ::GetDeviceCaps(m_dc, VERTRES);
    m_size = N2Size(horz, vert); 
}

N2Size N2Win32Drawer::getSize() const 
{
    return m_size;
}

uint32 N2Win32Drawer::getBitsPerPixel() const 
{
    int bits = ::GetDeviceCaps(m_dc, BITSPIXEL);
    int planes = ::GetDeviceCaps(m_dc, PLANES);
    return bits * planes;
}

uint32 N2Win32Drawer::getPixel(uint32 x, uint32 y) const 
{
    if(!m_size.inRectFromSize(x, y)) return 0;

    return ::GetPixel(m_dc, x, y);
}

void   N2Win32Drawer::setPixel(uint32 x, uint32 y)
{
    if(!m_size.inRectFromSize(x, y)) return;

    ::SetPixel(m_dc, x, y, m_color);
}

void   N2Win32Drawer::drawVertLine(uint32 x, uint32 y1, uint32 y2)
{
    ::MoveToEx(m_dc, x, y1, NULL);
   	::LineTo(m_dc, x, y2);
}

void   N2Win32Drawer::drawHorzLine(uint32 y, uint32 x1, uint32 x2)
{
    ::MoveToEx(m_dc, x1, y, NULL);
   	::LineTo(m_dc, x2, y);
}

void   N2Win32Drawer::fillRect(const N2Rect &rect)
{
    RECT r; 
    r.top = rect.top;
    r.bottom = rect.bottom;
    r.left = rect.left;
    r.right = rect.right;
    ::FillRect(m_dc, &r, (HBRUSH) (COLOR_WINDOW+1));
}

N2Palette* N2Win32Drawer::getPalette() const 
{
    return NULL;
}

void N2Win32Drawer::setWorldTransform(const N2WorldTransform &wt)
{
    XFORM xf = wt.getXFORM();
    if(!SetWorldTransform(m_dc, &xf))
    {
        N1Log(N1Log_Error, "N2Win32Drawer: SetWorldTransform failed with %u", GetLastError());
    }
}

N2WorldTransform N2Win32Drawer::getWorldTransform() const 
{
    XFORM xf;
    GetWorldTransform(m_dc, &xf);
    return N2WorldTransform(xf);
}

void N2Win32Drawer::setColor(const N2Color &color)
{
    m_color = (COLORREF)color;
    HPEN hp = ::CreatePen(PS_SOLID, 1, m_color);
    HGDIOBJ prev = ::SelectObject(m_dc, hp);
    ::DeleteObject(prev);
}

N2Color  N2Win32Drawer::getColor() const 
{
    return N2Color(m_color);
}

void     N2Win32Drawer::setBrush(N2Brush *brush)
{
    if(m_brush==brush) return;

    m_brush->release();
    m_brush = brush;
    m_brush->retain();

    createBrush(m_brush->fillColor());
}

N2Brush* N2Win32Drawer::getBrush() const 
{
    return m_brush;
}

N2Color  N2Win32Drawer::getPoint(const N2Point &point) const 
{
    return N2Color((COLORREF)getPixel(point.x, point.y));
}

void N2Win32Drawer::drawPoint(const N2Point &point)
{
    ::SetPixel(m_dc, point.x, point.y, m_color);
}

void N2Win32Drawer::drawLine(const N2Point &from, const N2Point &to)
{
    ::MoveToEx(m_dc, from.x, from.y, NULL);
   	::LineTo(m_dc, to.x, to.y);
}

void N2Win32Drawer::drawRect(const N2Rect &rect)
{
    ::Rectangle(m_dc, rect.left, rect.top, rect.right, rect.bottom);
}

void N2Win32Drawer::drawShape(const N2Point *points, uint32 count)
{
    POINT *_pnts = allocPoints(count);
    POINT *cur = _pnts;
    const N2Point *from = points;
    for(uint32 i=0;i<count;i++) 
    {
        cur->x = from->x;
        cur->y = from->y;
        cur++; from++;
    }
    ::Polygon(m_dc, _pnts, count);
    freePoints(_pnts);
}

#endif
